package org.home.tax.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import org.hibernate.Transaction;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;

/**
 *
 * @author TIN Nguyen
 */
public abstract class AbstractRepository<INSTANCE_CLASS, PRIMARY_KEY_CLASS> implements Repository<INSTANCE_CLASS, PRIMARY_KEY_CLASS> {

    protected Session session = HibernateUtil.getSessionFactory().openSession();
    private Class<INSTANCE_CLASS> entityClass;

    public AbstractRepository() {
        Type[] types = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();

        if (types[0] instanceof ParameterizedType) {
            // If the class has parameterized types, it takes the raw type.
            ParameterizedType type = (ParameterizedType) types[0];
            entityClass = (Class<INSTANCE_CLASS>) type.getRawType();
        } else {
            entityClass = (Class<INSTANCE_CLASS>) types[0];
        }
    }
    
    public void saveOrUpdate(INSTANCE_CLASS instance) {
        Transaction tx = session.beginTransaction();
        session.saveOrUpdate(instance);
        tx.commit();
    }

    public void delete(PRIMARY_KEY_CLASS id) {
        Transaction tx = session.beginTransaction();
        Object target = findById(id);
        session.delete(target);
        tx.commit();
    }

    public INSTANCE_CLASS findById(PRIMARY_KEY_CLASS id) {
        return (INSTANCE_CLASS) session.createCriteria(entityClass).add(Expression.idEq(id)).uniqueResult();
    }

    public List<INSTANCE_CLASS> findAll() {
        return session.createCriteria(entityClass).list();
    }

    public List<INSTANCE_CLASS> findAllByCriteria(Criteria criteria) {
        return criteria.list();
    }

}